home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / dev / debug / enforcr36.lzh / Enforcer.doc < prev    next >
Text File  |  1993-03-02  |  40KB  |  936 lines

  1. TABLE OF CONTENTS
  2.  
  3. Enforcer
  4. LawBreaker
  5. Move4K
  6. SegTracker
  7. Enforcer                                                             Enforcer
  8.  
  9.    NAME
  10.     Enforcer V37 - An advanced version of Enforcer - Requires V37
  11.  
  12.    SYNOPSIS
  13.     Enforcer - A tool to watch for illegal memory accesses
  14.  
  15.    FUNCTION
  16.     Enforcer will use the MMU in the advanced 680x0 processors
  17.     to set up MMU tables to watch for illegal accesses to memory
  18.     such as the low-page and non-existent pages.
  19.  
  20.     To use, run Enforcer (plus any options you may wish)
  21.     If you wish to detach, just use RUN >NIL: <NIL: to start it.
  22.     You can also start it from the Workbench.  When started from Workbench,
  23.     Enforcer will read the tooltypes of its icon or selected project icon
  24.     for its options.  (See the sample project icons)
  25.  
  26.     Enforcer should only be run *after* SetPatch.
  27.  
  28.     If SegTracker is running in the system when Enforcer is started,
  29.     Enforcer will use the public SegTracker seglist tracking for
  30.     identifying the hits.
  31.  
  32.    INPUTS
  33.     The options for Enforcer are as follows:
  34.  
  35.     QUIET/S        - This tells Enforcer to not complain about any invalid
  36.                      access and to just build MMU tables for cache setting
  37.                      reasons -- mainly used in conjunction with an
  38.                      Amiga BridgeBoard in a 68030 environment so that
  39.                      the system can run with the data cache turned on.
  40.                      In this case,
  41.                                     RUN >NIL: Enforcer QUIET
  42.                      should be placed into the startup-sequence right
  43.                      after SetPatch.
  44.  
  45.     TINY/S         - This tells Enforcer to output a minimal hit.  The
  46.                      output is basically the first line of the Enforcer
  47.                      hit.  (see below)
  48.  
  49.     SMALL/S        - This tells Enforcer to output the hit line, the
  50.                      USP: line, and the Name: line.  (This means that
  51.                      no register or stack display will be output)
  52.  
  53.     SHOWPC/S       - This tells Enforcer to also output the two lines
  54.                      that contain the memory area around the PC where
  55.                      the hit happened.  Useful for disassembly.
  56.                      This option will not do anything if QUIET, SMALL or
  57.                      TINY output modes are selected.
  58.  
  59.     STACKLINES/K/N - This lets you pick the number of lines of stack
  60.                      backtrace to display.  The default is 2.  If set
  61.                      to 0, no stack backtrace will be displayed.  There
  62.                      is no enforced limit on the number of lines.
  63.  
  64.     STACKCHECK/S   - This option tells Enforcer that you wish all of
  65.                      the long words displayed in the stack to be checked
  66.                      against the global seglists via SegTracker.
  67.                      This will tell you what seglist various return
  68.                      addresses are on the stack.  If you are not
  69.                      displaying stack information in the Enforcer hit
  70.                      then STACKCHECK will have nothing to check.
  71.                      If you are displaying stack information, then
  72.                      each long word will be check and only those which
  73.                      are in one of the tracked seglists will be
  74.                      displayed in a SegT: line.
  75.  
  76.     DEADLY/S       - This makes Enforcer be a bit more nasty.  Normally,
  77.                      when an illegal read happens, Enforcer returns 0
  78.                      as the result of this read.  With this option,
  79.                      Enforcer will return $ABADFEED as the read data.
  80.                      This option can make programs with Enforcer hits
  81.                      cause even more hits.
  82.  
  83.     FSPACE/S       - This option will make the special $00F00000 address
  84.                      space available for writing to.  This is useful for
  85.                      those people with $00F00000 boards.  Mainly Commodore
  86.                      internal development work -- should only be used
  87.                      in that enviroment.
  88.  
  89.     VERBOSE/S      - This option will make Enforcer display information
  90.                      as to the mapping of the I/O boards and other
  91.                      technical information.  This information maybe useful
  92.                      in specialized debugging.
  93.  
  94.     PARALLEL/S     - This option will make Enforcer use the parallel port
  95.                      hardware rather than the serial port for output.
  96.  
  97.     RAWIO/S        - This option will make Enforcer stuff the hit report
  98.     (special IO)     into an internal buffer and then from the main
  99.                      Enforcer process output the results via the
  100.                      RawPutChar() EXEC debugging LVO.  Since the output
  101.                      happens on the Enforcer task it is possible for a
  102.                      hit that ends in a system crash to not be able to
  103.                      be reported.  This option is here such that tools
  104.                      which can redirect debugging output can redirect
  105.                      the Enforcer output too.
  106.  
  107.     FILE/K         - This option will make Enforcer output the hit report
  108.     (special IO)     but to a file insted of sending it to the hardware
  109.                      directly or using the RAWIO LVO.  A good example of
  110.                      such a file is CON:0/0/640/100/HIT/AUTO/WAIT.
  111.                      Another thing that can be done is to have a program
  112.                      sit on a named pipe and have Enforcer output to it.
  113.                      This program can then do whatever it feels like with
  114.                      the Enforcer hits.  (Such as decode them, etc.)
  115.                      *NOTE*  It is not a good idea to have Enforcer hits
  116.                      go to a file on a disk as if the system crashes
  117.                      during/after the Enforcer hit, the disk may
  118.                      become corrupt.
  119.  
  120.     STDIO/S        - This option will make Enforcer output the hit report
  121.     (special IO)     to STDOUT.  This option only works from the CLI as it
  122.                      requires STDOUT.  It is best used with redirection or
  123.                      pipes.
  124.  
  125.     BUFFERSIZE/K/N - This lets you set Enforcer's internal output buffer
  126.                      for the special I/O options.  This option is only
  127.                      valid with the RAWIO, FILE, or STDIO options.
  128.                      The minimum setting is 8000.  The default is 8000.
  129.                      Having the right amount of buffer is rather
  130.                      important for the special I/O modes.  The reason
  131.                      is due to the fact that no operating system calls
  132.                      can be made from a bus error.  Thus, in the
  133.                      special I/O mode, Enforcer must store the output
  134.                      in this buffer and, via some special magic,
  135.                      wake up the Enforcer task to read the buffer and
  136.                      write it out as needed.  However, if a task is
  137.                      in Forbid() or Disable() when the Enforcer hit
  138.                      happens, the Enforcer task will not be able to
  139.                      output the results of the hit.  This buffer lets
  140.                      a number of hits happen even if the Enforcer task
  141.                      was unable to do the I/O.  If the number of
  142.                      hits that happen before the I/O was able to
  143.                      run gets too large, the last few hits will either
  144.                      be cut off completely or contain only partial
  145.                      information.
  146.  
  147.     INTRO/K        - This optional introduction string will be output
  148.                      at the start of every Enforcer hit.  For example:
  149.                      INTRO="*NBad Program!"   The default is no string.
  150.  
  151.     PRIORITY/K/N   - This lets you set Enforcer's I/O task priority.
  152.                      The default for this priority is 99.  In some
  153.                      special cases, you may wish to adjust this.
  154.                      It is, however, recommended that if you are using
  155.                      one of the special I/O options (RAWIO, FILE, or
  156.                      STDIO) that you keep the priority rather high.
  157.                      The value is not checked for valid priority range.
  158.  
  159.     ON/S           - Mainly for completeness.  If not specified, it
  160.                      is assumed you want to turn ON Enforcer.
  161.  
  162.     QUIT=OFF/S     - Tells Enforcer to turn off.  Enforcer can also be
  163.                      stopped by sending a CTRL-C to its process.
  164.  
  165.    RESULTS
  166.     When running, a set of MMU tables that map addresses that are not
  167.     in the system's address map as invalid such that any access to them
  168.     will cause an access fault.  Enforcer will then display this fact
  169.     and generate a diagnostic message as to what the illegal access
  170.     was.  The first memory page (the one starting at location 0) is
  171.     also marked as invalid as many programming errors cause invalid
  172.     access to these addresses.  These addresses are completely off
  173.     limits to applications.
  174.  
  175.     When an    access violation happens, a report such as the following
  176.     is output.
  177.  
  178. WORD-WRITE to  00000000        data=4444       PC: 07895CA4
  179. USP:  078D692C SR: 0000 SW: 0729  (U0)(-)(-)  TCB: 078A2690
  180. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  181. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  182. Stck: 00000000 07848E1C 00009C40 078A30B4 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  183. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 078E9048 00011DA8 DEADBEEF
  184. PC-8: AAAA1111 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C40000
  185. PC *: 522E0127 201433FC 400000DF F09A522E 012611C7 00CE4EAE FF7642B8 0324532E
  186. SegT: 07895CA4 - "lawbreaker"  Hunk 0000 Offset 0000007C
  187. Name: "New_Shell"  CLI: "lawbreaker"  Hunk 0000 Offset 0000007C
  188.  
  189. LONG-READ from AAAA4444                        PC: 07895CA8
  190. USP:  078D692C SR: 0015 SW: 0749  (U0)(F)(-)  TCB: 078A2690
  191. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  192. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  193. Stck: 00000000 07848E1C 00009C40 078A30B4 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  194. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 078E9048 00011DA8 DEADBEEF
  195. PC-8: 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C40000 522E0127
  196. PC *: 201433FC 400000DF F09A522E 012611C7 00CE4EAE FF7642B8 0324532E 01266C08
  197. SegT: 07895CA8 - "lawbreaker"  Hunk 0000 Offset 00000080
  198. Name: "New_Shell"  CLI: "lawbreaker"  Hunk 0000 Offset 00000080
  199.  
  200.     Here is a breakdown of what these reports are saying:
  201.  
  202.     The first line of each report describes the access violation
  203.     and where it happened from.  In the case of a WRITE, the data
  204.     that was being written will be displayed as well.  If an instruction
  205.     mode access caused the fault, there will be an (INST) in the line.
  206.  
  207.     The first line may also contain the BUS ERROR message.  This will
  208.     be displayed when an address that is valid in the system lists
  209.     causes a physical bus fault during the access.  This usually
  210.     will happen with plug-in cards or when a hardware problem causes
  211.     some form of system fault.  Watch out, if this does show up, your
  212.     system may be unstable and/or unreliable.
  213.  
  214.     The second line (starts USP:) displays the USER stack pointer (USP),
  215.     the status register (SR:), the special status word (SW:).  It then
  216.     displays the supervisor/user state and the interrupt level.  This
  217.     will be from (U0) to (U7) or (S0) to (S7)  (S=Supervisor)  Next
  218.     is the forbid state (F=forbid, -=not) and the disable state (D or -)
  219.     of the task that was running when the access fault took place.
  220.     Finally, the task control block address is displayed (TCB:)
  221.  
  222.     The next two lines contain the data and address register dumps from
  223.     when the access fault happened.  Note that A7 is not listed here.
  224.     It is the stack pointer and is listed as USP: in the line above.
  225.  
  226.     Then come the lines of stack backtrace.  These lines show the
  227.     data on the stack.  If the stack is in invalid memory, Enforcer will
  228.     display a message to that fact.
  229.  
  230.     If SegTracker was installed before Enforcer, the "SegT:" lines
  231.     will display in which seglist the given addresses are in based on the
  232.     global tracking that SegTracker does.  (See docs on SegTracker)
  233.     If no seglist match is found, no lines will be displayed.
  234.     One line will be displayed for each of the stack longwords asked
  235.     for (see the STACKCHECK option) and one line for the PC address of
  236.     the Enforcer hit.  (The PC line is always checked for is SegTracker
  237.     is installed.)  The lines are in order: hit, first stack find,
  238.     second stack find, etc.  This is useful for tracking down who
  239.     called the routine that caused the Enforcer hit.
  240.  
  241.     Next, optionally, comes the data around the program counter when the
  242.     access fault happened.  The first line (PC-8:) is the 8 long-words
  243.     before the program counter.  The second line starts at the program
  244.     counter and goes for 8 long words.
  245.  
  246.     The last line displays the name of the task that was running when
  247.     the access fault took place.  If the task was a CLI, it will display
  248.     the name of the CLI command that was running.  If the access fault
  249.     was found to have happened within the seglist of a loaded program,
  250.     the segment number and the offset from the start of the segment will
  251.     be displayed.  (Note that this works for any LoadSeg()'ed process)
  252.  
  253.     Note that the name will display as "Processor Interrupt Level x"
  254.     if the access happened in an interrupt.
  255.  
  256.    WARNING
  257.     Enforcer is for software testing.  In this role it is vital.
  258.     Software that causes Enforcer hits may well not be able to run on
  259.     newer hardware.  (Enforcer hits of high addresses on systems not
  260.     running Enforcer but with a 68040 will most likely crash the system)
  261.     Future systems and hardware will make this even more important.  The
  262.     system can NOT survive software that causes Enforcer hits.
  263.  
  264.     However, Enforcer is NOT a system protector.  As a side effect, it
  265.     may well keep a system from crashing when Enforcer hits happen, but
  266.     it may just as well make the software crash earlier.  Enforcer is
  267.     mainly a development and testing tool.
  268.  
  269.     Enforcer causes    no ill effects if no software causes an Enforcer hit.
  270.  
  271.    NOTES
  272.     This new Enforcer is a completely new program.  Bryce Nesbitt came
  273.     up with the original "Enforcer" that has been instrumental to the
  274.     improvement in the quality of software on the Amiga.  The Amiga
  275.     users and developers owe him a great deal for this.  Thank you Bryce!
  276.  
  277.     This Enforcer came about due to a number of needs.  These included
  278.     the need for more output options and better performance.  It also
  279.     marks the removal of all kludges that were in the older versions.
  280.     Also, some future plans required some of these changes...
  281.  
  282.     In addition, the complete redesign was needed in order to also
  283.     support the 68040.  The internal design of Enforcer is now set up
  284.     such that CPU/MMU specific code can be cleanly accessed from the
  285.     general house keeping aspect of the code.  The MMU bus error
  286.     handling is, however, 100% CPU specific.
  287.  
  288.     Since AbsExecBase is in low memory, reads of this address are slower
  289.     with Enforcer running.  Caching AbsExecBase locally is highly
  290.     recommended since it is in CHIP memory and on systems with FAST
  291.     memory, it will be faster to access the local cached value. (In
  292.     addition to the performance increase when running Enforcer) Note
  293.     that doing many reads of location 4 will hurt interrupt performance.
  294.  
  295.     When the Amiga produces an ALERT, EXEC places some magic numbers
  296.     into some special locations in low memory.  The exact pattern
  297.     changes between versions of the operating system.
  298.  
  299.     Enforcer will patch the EXEC function ColdReboot() in an attempt to
  300.     "get out of the way" when someone tries to reboot the system.
  301.     Enforcer will clean up as much as possible the MMU tables and then
  302.     call the original LVO.  When Enforcer is asked to quit, it will
  303.     check to make sure it can remove itself from this LVO. If it can
  304.     not, it will not quit at that time.  If run from the shell, it will
  305.     display a message saying that it tried but could not exit.  Enforcer
  306.     will continue to be active and you can try later to deactivate it.
  307.  
  308.    68020 NOTES
  309.     The 68020 does not have a built-in MMU but has a co-processor
  310.     feature that lets an external MMU be connected.  Enforcer MMU code
  311.     is designed for use with 68851 MMU.  This is the some-what 68030
  312.     compatible MMU by Motorola.  Enforcer uses the same code for both
  313.     the 68030 and the 68020/68851.  For this reason, 68020/68851 users
  314.     should see the 68030 NOTES section.
  315.  
  316.    68030 NOTES
  317.     The 68030 uses cycle/instruction continuation and will
  318.     supply the data on reads and ignore writes during an access
  319.     fault rather than let the real bus cycle happen.  This means
  320.     that on a fault caused by MMU tables, no bus cycle to the
  321.     fault address will be generated.  (For those of you with analyzers)
  322.  
  323.     In some cases, the 68030 will have advanced the Program Counter
  324.     past the instruction by the time the access fault happens.
  325.     This is usually only on WRITE faults.  For this reason, the PC
  326.     may either point at the instruction that caused the fault or
  327.     just after the instruction that caused the fault.  (Which could
  328.     mean that it is pointing to the middle of the instruction
  329.     that caused the fault.)
  330.  
  331.     Note that there is a processor called 68EC030.  This processor
  332.     has a disabled or defective MMU.  However, it may function well
  333.     enough for Enforcer to think it has a fully functional MMU and
  334.     thus Enforcer will attempt to run.  However, even if it looks like
  335.     the MMU is functioning, it is not fully operational and thus may
  336.     cause strange system activity and even crashes.  Do not assume
  337.     that Enforcer is safe to use on 68EC030 systems.
  338.  
  339.    68040 NOTES
  340.     Enforcer, on the 68040, *requires* that the 68040.library be
  341.     installed and it requires an MMU 68040 CPU.  The 68EC040 does not
  342.     have a MMU.  The 68LC040 does have an MMU and is supported. Enforcer
  343.     will work best in a system with the 68040.library 37.10 or better
  344.     but it does know how to deal with systems that do not have that
  345.     version.
  346.  
  347.     Due to the design of the 68040, Enforcer is required to do a number
  348.     of things differently.  For example, the MMU page size can only be
  349.     either 8K or 4K.  This means that to protect the low 1K of memory,
  350.     Enforcer will end up having to mark the first 4K of memory as
  351.     invalid and emulate the access to the 3K of that memory that is
  352.     valid. For this reason Enforcer moves a number of possible
  353.     structures from the first 4K of memory to higher addresses.  This
  354.     means that the system will continue to run at a reasonable speed.
  355.     The first time Enforcer is run it may need to allocate memory for
  356.     these structures that it will move.  Enforcer can never return this
  357.     memory to the system.
  358.  
  359.     In addition to the fact that the 68040 MMU table size is different,
  360.     the address fault handling is also different.  Namely, the 68040 can
  361.     only rerun the cycle and not continue it like the 68030. This means
  362.     that on a 68040, the page must be made available first and then made
  363.     unavailable.  Make this work, Enforcer will switch the instruction
  364.     that caused the error into trace mode and let it run with a special
  365.     MMU setup.  When the trace exception comes in, the MMU is set up
  366.     back to the way it was.  Enforcer does its best to keep debuggers
  367.     working.  Note, however, that the interrupt level during a trace of
  368.     a READ will end up being set to 7.  This is to prevent interrupts
  369.     from changing the order of trace/MMU table execution.  The level
  370.     will be restored to the original state before continuing.  Since T0
  371.     mode tracing is also supported, there are also some changes in the
  372.     way it operates.  T0 mode tracing is defined, on the 68040, to cause
  373.     a trace whenever the instruction pipeline needed to be reloaded.
  374.     While on the 68020/030 processors this was normally only for the
  375.     branch instructions, in the 68040 this includes a large number of
  376.     other instructions.  (Including NOP!)  Anyway, if an Enforcer hit
  377.     happens while in T0 tracing mode, the trace will happen even on
  378.     instructions that normally would not cause a T0 mode trace.  Since
  379.     this may actually help in debugging and because it was not possible
  380.     to do anything else, this method of operation is deemed acceptable.
  381.  
  382.     Another issue with the 68040 is that WRITE faults happen *after* the
  383.     instruction has executed.  (Except for MOVEM)  In fact, it is common
  384.     for the 68040 to execute one or more extra instructions before the
  385.     WRITE fault is executed.  This design makes the 68040 much faster,
  386.     but it also makes the Program Counter value that Enforcer can report
  387.     for the fault much less likely to be pointing to the instruction
  388.     that caused it.  The worst cases are sequences such as a write fault
  389.     followed by a branch instruction.  In these cases, the branch is
  390.     usually already executed before the write fault happens and thus the
  391.     PC will be pointing to the target of the branch.  There is nothing
  392.     that can be done within Enforcer to help out here.  You will just
  393.     need to be aware of this and deal with it as best as possible.
  394.  
  395.     Along with the above issue, is the fact that since a write fault may
  396.     be delayed, a read fault may happen before the write fault shows up.
  397.     Internally, enforcer does not do special processing for these and
  398.     they will not show up.  Since another hit was happening anyway, it
  399.     is felt that it is best to just not report the hit.  Along the same
  400.     lines, the hit generated from a MOVEM instruction may only show as a
  401.     single hit rather than 1 for each register moved.
  402.  
  403.     On the Amiga, MOVE16 is not supported 100%.  Causing an Enforcer hit
  404.     with a MOVE16 will cause major problems and maybe cause Enforcer or
  405.     your task to lock.  Since MOVE16 is not supported, this is not a
  406.     major issue.  Just watch out if you are using this 68040
  407.     instruction.  (Also, watch out for the 68040 CPU bug with MOVE16)
  408.  
  409.     The functions CachePreDMA(), CachePostDMA(), and CacheControl() are
  410.     patched when the 68040 MMU is turned on by Enforcer.  These
  411.     functions are patched such the issues with DMA and the 68040
  412.     COPYBACK data caches are addressed.  The 68040.library normally
  413.     deals with this, however since Enforcer turns on the MMU, the method
  414.     of dealing with it in the 68040.library will not work. For this
  415.     reason, Enforcer will patch these and implement the required fix for
  416.     when the MMU is on.  When Enforcer is asked to exit, it will check
  417.     if it can remove itself from these functions.  If it can not, it
  418.     will ignore the request to exit.  If Enforcer was run from the CLI,
  419.     it will print a message saying that it can not exit when the attempt
  420.     is made.
  421.  
  422.    WRITING DEBUGGERS
  423.     If you wish to make a debugger that works with Enforcer to help
  424.     pinpoint Enforcer hits in the application and not cause Enforcer
  425.     hits itself, here are some simple tips and a bit of code.
  426.  
  427.    DEBUGGERS:  TRAPPING A HIT
  428.     To trap a hit requires a number of things to work.
  429.  
  430.     First, the debugger itself must never cause an Enforcer hit.
  431.     For help on that, see the "DEBUGGERS: NOT CAUSING A HIT"
  432.  
  433.     Second, the debugger must be global.  That is, you must be
  434.     able to deal with a task getting a hit that is not the task
  435.     under test.  There are a number of simple ways to deal with
  436.     this, and I will leave this up to the debugger writer.
  437.  
  438.     Third, the debugger must start *AFTER* Enforcer starts.
  439.     If it is started before Enforcer, the hits will not be
  440.     trapped.  (Note that this is not a problem)
  441.  
  442.     Now, given the above, the following bits of code can be
  443.     used to get the debugger to switch into single-step mode
  444.     at the point of the Enforcer hit.  You can also set some
  445.     data value here to tell your debugger about this.
  446.  
  447.     ;
  448.     ; The following code is inserted into the bus error vector.
  449.     ; Make sure you follow the VBR to find the vector.
  450.     ; Store the old vector in the address OldVector
  451.     ; Make sure you already have the single-step trap vector
  452.     ; installed before you install this.  Note that any extra
  453.     ; code you add in the comment area *MUST NOT* cause a bus
  454.     ; fault of any kind, including reading of location 4.
  455.     ;
  456.     ; This is the 68020 and 68030 version...
  457.     ;
  458.     OldVector:      ds.l    1                       ; One long word
  459.     NewVector:      move.l  OldVector(pc),-(sp)     ; Ready to return
  460.                     cmp.l   #4,$10+4(sp)            ; 68020 and 68030
  461.                     beq.s   TraceSkip               ; If AbsExecBase, OK
  462.                     bset.b  #7,4(sp)                ; Set trace bit...
  463.                     ; If you have any other data to set, do it now...
  464.                     ; Set as setting the EnforcerHit bit in your data...
  465.     TraceSkip:      rts
  466.     ;
  467.     ; This is the 68040 version...
  468.     ;
  469.     NewVector040:   move.l  OldVector(pc),-(sp)     ; Ready to return
  470.                     cmp.l   #4,$14+4(sp)            ; 68040
  471.                     beq.s   TraceSkip040            ; If AbsExecBase, OK
  472.                     bset.b  #7,4(sp)                ; Set trace bit...
  473.                     ; If you have any other data to set, do it now...
  474.                     ; Set as setting the EnforcerHit bit in your data...
  475.     TraceSkip040:   rts
  476.  
  477.    DEBUGGERS:  NOT CAUSING A HIT
  478.     In order not to cause Enforcer hits, you can do a number
  479.     of things.  The easiest is to test the address with the TypeOfMem()
  480.     EXEC function.  If TypeOfMem() returns 0, the address is not
  481.     in the memory lists.  However, this does not mean it is not a
  482.     valid address in all cases.  (ROM, chip registers, I/O boards)
  483.     For those cases, you can build a "valid memory access table"
  484.     much like Enforcer does.  Here is the code from Enforcer for
  485.     the base memory tables:
  486.  
  487.     /*
  488.      * Mark_Address(mmu,start address,length,type)
  489.      */
  490.  
  491.     /*
  492.      * Special case the first page of CHIP RAM
  493.      */
  494.     mmu=Mark_Address(mmu,0,0x1000,INVALID | NONCACHEABLE);
  495.  
  496.     /*
  497.      * Map in the free memory
  498.      */
  499.     Forbid();
  500.     mem=(struct MemHeader *)SysBase->MemList.lh_Head;
  501.     while (mem->mh_Node.ln_Succ)
  502.     {
  503.       mmu=Mark_Address(mmu,
  504.                        (ULONG)(mem->mh_Lower),
  505.                        (ULONG)(mem->mh_Upper)-(ULONG)(mem->mh_Lower),
  506.                        ((MEMF_CHIP & TypeOfMem(mem->mh_Lower)) ?
  507.                          (NONCACHEABLE | VALID) : (CACHEABLE | VALID)));
  508.       mem=(struct MemHeader *)(mem->mh_Node.ln_Succ);
  509.     }
  510.     Permit();
  511.  
  512.     /*
  513.      * Map in the autoconfig boards
  514.      */
  515.     if (ExpansionBase=OpenLibrary("expansion.library",0))
  516.     {
  517.     struct    ConfigDev    *cd=NULL;
  518.  
  519.       while (cd=FindConfigDev(cd,-1L,-1L))
  520.       {
  521.         /* Skip memory boards... */
  522.         if (!(cd->cd_Rom.er_Type & ERTF_MEMLIST))
  523.         {
  524.           mmu=Mark_Address(mmu,
  525.                            (ULONG)(cd->cd_BoardAddr),
  526.                            cd->cd_BoardSize,
  527.                            VALID | NONCACHEABLE);
  528.         }
  529.       }
  530.       CloseLibrary(ExpansionBase);
  531.     }
  532.  
  533.     /*
  534.      * Now for the control areas...
  535.      */
  536.     mmu=Mark_Address(mmu,0x00BC0000,0x00040000,VALID | NONCACHEABLE);
  537.     mmu=Mark_Address(mmu,0x00D80000,0x00080000,VALID | NONCACHEABLE);
  538.  
  539.     /*
  540.      * and the ROM...
  541.      */
  542.     mmu=Mark_Address(mmu,
  543.                      0x00F80000,
  544.                      0x00080000,
  545.                      VALID | CACHEABLE | WRITEPROTECT);
  546.  
  547.     /*
  548.      * If the credit card resource, make the addresses valid...
  549.      */
  550.     if (OpenResource("card.resource"))
  551.     {
  552.       mmu=Mark_Address(mmu,0x00600000,0x00440002,VALID | NONCACHEABLE);
  553.     }
  554.  
  555.     /*
  556.      * Check for ReKick/ZKick/KickIt
  557.      */
  558.     if ((((ULONG)(SysBase->LibNode.lib_Node.ln_Name)) >> 16) == 0x20)
  559.     {
  560.       mmu=Mark_Address(mmu,
  561.                        0x00200000,
  562.                        0x00080000,
  563.                        VALID | CACHEABLE | WRITEPROTECT);
  564.     }
  565.  
  566.    SEE ALSO
  567.     "A master's secrets are only as good as the
  568.      master's ability to explain them to others."  -  Michael Sinz
  569.  
  570.    BUGS
  571.     None?
  572.  
  573. LawBreaker                                                         LawBreaker
  574.  
  575.    NAME
  576.     LawBreaker - A quicky test of Enforcer
  577.  
  578.    SYNOPSIS
  579.     This is a quick test of Enforcer and its reporting abilities.
  580.  
  581.    FUNCTION
  582.     This program is used to make sure that Enforcer is correctly
  583.     installed and operating.  LawBreaker works from either the CLI
  584.     or Workbench.  It will try to read and write certain memory
  585.     areas that will cause an Enforcer hit or four.
  586.  
  587.    INPUTS
  588.     Just run it...
  589.  
  590.    RESULTS
  591.     When running Enforcer, you will see some output from Enforcer.
  592.     Output on a 68030 machine would look something like this:
  593.  
  594. WORD-WRITE to  00000000        data=0000       PC: 0783AC6A
  595. USP:  078CAAEC SR: 0004 SW: 0729  (U0)(-)(-)  TCB: 078AADF8
  596. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  597. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  598. Stck: 00000000 0784991C 00009C40 078AB81C BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  599. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 00000000 006B54E0 ABADCAFE
  600. PC-8: AAAA1111 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C00000
  601. PC *: 522E0127 201433FC 400000DF F09A522E 012611C1 01004EAE FF7621C0 0104532E
  602. Name: "Shell"  CLI: "NewTest:LawBreaker"  Hunk 0000 Offset 0000007A
  603.  
  604. LONG-READ from AAAA4444                        PC: 0783AC6E
  605. USP:  078CAAEC SR: 0015 SW: 0749  (U0)(F)(-)  TCB: 078AADF8
  606. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  607. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  608. Stck: 00000000 0784991C 00009C40 078AB81C BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  609. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 00000000 006B54E0 ABADCAFE
  610. PC-8: 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C00000 522E0127
  611. PC *: 201433FC 400000DF F09A522E 012611C1 01004EAE FF7621C0 0104532E 01266C08
  612. Name: "Shell"  CLI: "NewTest:LawBreaker"  Hunk 0000 Offset 0000007E
  613.  
  614. BYTE-WRITE to  00000100        data=11         PC: 0783AC80
  615. USP:  078CAAEC SR: 0010 SW: 0711  (U0)(F)(D)  TCB: 078AADF8
  616. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  617. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  618. Stck: 00000000 0784991C 00009C40 078AB81C BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  619. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 00000000 006B54E0 ABADCAFE
  620. PC-8: 2A7CAAAA 555531C0 0000522E 01272014 33FC4000 00DFF09A 522E0126 11C10100
  621. PC *: 4EAEFF76 21C00104 532E0126 6C0833FC C00000DF F09A201F 66024E75 22404EEE
  622. Name: "Shell"  CLI: "NewTest:LawBreaker"  Hunk 0000 Offset 00000090
  623.  
  624. LONG-WRITE to  00000104        data=00000000   PC: 0783AC88
  625. USP:  078CAAEC SR: 0014 SW: 0709  (U0)(-)(D)  TCB: 078AADF8
  626. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  627. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  628. Stck: 00000000 0784991C 00009C40 078AB81C BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  629. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 00000000 006B54E0 ABADCAFE
  630. PC-8: 0000522E 01272014 33FC4000 00DFF09A 522E0126 11C10100 4EAEFF76 21C00104
  631. PC *: 532E0126 6C0833FC C00000DF F09A201F 66024E75 22404EEE FE860024 5645523A
  632. Name: "Shell"  CLI: "NewTest:LawBreaker"  Hunk 0000 Offset 00000098
  633.  
  634.    NOTES
  635.     If enforcer is not running, the program should not cause the
  636.     system to crash.  It will, however, write to certain areas
  637.     of low memory.  Also, it will cause read access of some
  638.     addresses that may not exist.  This may cause bus faults.
  639.  
  640.    SEE ALSO
  641.     "Quantum Physics:  The Dreams that Stuff is made of." - Michael Sinz
  642.  
  643.    BUGS
  644.     There are 4 known Enforcer hits in this code, however, they
  645.     will not be fixed.  ;^)
  646.  
  647. Move4K                                                                 Move4K
  648.  
  649.    NAME
  650.     Move4K - Moves as much out of the lower 4K of RAM as possible
  651.  
  652.    SYNOPSIS
  653.     On 68040 systems, as much of the lower 4K of CHIP RAM is removed
  654.     from system use.
  655.  
  656.    FUNCTION
  657.     On 68040 systems the MMU page sizes are 4K and 8K.  Enforcer
  658.     uses the 4K page size.  Since watching for hits of low memory
  659.     is a vital part of Enforcer, this means that the first 4K
  660.     of RAM will be marked invalid.  On current systems, only
  661.     the first 1K of RAM is invalid and thus 3K of RAM in that
  662.     first 4K will end up needing to be emulated in Enforcer.
  663.     In order to reduce the overhead that this causes (and the
  664.     major performance loss) this program will try to move as much
  665.     from that first 4K as possible and make any of the free
  666.     memory within the first 4K inaccessible.
  667.  
  668.     Enforcer itself also has this logic, but it may be useful
  669.     to be able to run this program as the first program in
  670.     the Startup-Sequence (*AFTER* SetPatch) to try to limit
  671.     the number of things that may use the lower 4K of RAM.
  672.  
  673.    INPUTS
  674.     Just run it...  Can be run from CLI or Workbench
  675.  
  676.    RESULTS
  677.     Any available memory in the lower 4K of CHIP RAM is removed
  678.     plus a special graphics buffer is moved if it needs to be.
  679.     After running this program you may have a bit less CHIP RAM
  680.     than before.  You can run this program as many times as you
  681.     wish since it only moves things if it needs to.
  682.  
  683.    NOTES
  684.     This program will do nothing on systems without a 68040.
  685.     It does not, however, check for the MMU and thus it will
  686.     move the lower 4K even if the CPU is not able to run Enforcer.
  687.  
  688.     V39 of the operating system already does have the lowest
  689.     MMU page empty and thus this program will effectively do
  690.     nothing under V39.
  691.  
  692.    SEE ALSO
  693.     "Eloquence is vehement simplicity"
  694.  
  695.    BUGS
  696.     None.
  697.  
  698. SegTracker                                                         SegTracker
  699.  
  700.    NAME
  701.     SegTracker - A global SegList tracking utility
  702.  
  703.    SYNOPSIS
  704.     A global tracking utility for disk loaded files including
  705.     libraries and devices.  If placed in the startup-sequence
  706.     right after SetPatch, it will track all disk loaded segments
  707.     (other than those loaded by SetPatch)
  708.  
  709.    FUNCTION
  710.     SegTracker will patch the DOS LoadSeg(), NewLoadSeg(), and UnLoadSeg()
  711.     functions in order to track the SegLists that are loaded.
  712.     SegTracker keeps these seglist stored in a "safe" manner and
  713.     even handles programs which SegList split.
  714.  
  715.     The first time the program is run, it installs the patches
  716.     and semaphore.  After that point, it just finds the semaphore
  717.     and uses it.
  718.  
  719.     By using SegTracker, it will be possible to better identify
  720.     where Enforcer hits come from when dealing with libraries
  721.     and devices.  Basically, it is a system-global Hunk-o-matic.
  722.  
  723.     External programs can then pass in an address to SegTracker
  724.     either via the command line or via the given function pointer
  725.     in the SegTracker semaphore and get back results as to what
  726.     hunk and offset the address is at.
  727.  
  728.     To work with the function directly, you need to find the
  729.     the semaphore of "SegTracker" using FindSemaphore().
  730.     The structure found will be the following:
  731.  
  732.     struct  SegSem
  733.     {
  734.     struct  SignalSemaphore seg_Semaphore;
  735.             SegTrack        *seg_Find;
  736.     };
  737.  
  738.     The function pointer points to a routine that takes an address
  739.     and two pointers to long words for returning the Segment number
  740.     and Offset within the segment.  The function returns the name
  741.     of the file loaded.  Note that you must call this function
  742.     while in Forbid() and then copy the name as the seglist may
  743.     be UnLoadSeg'ed at any moment and the name string will then
  744.     no longer be in memory.
  745.  
  746.     typedef    char (* __asm SegTrack(register __a0 ULONG Address,
  747.                                    register __a1 ULONG *SegNum,
  748.                                    register __a2 ULONG *Offset));
  749.  
  750.     The above is for use in C code function pointer prototype
  751.     in SAS/C 5 and 6.
  752.  
  753.    INPUTS
  754.     SHOW/S  - Shows all of the segments being tracked.
  755.  
  756.     DUMP/S  - Displays all of the segment elements being tracked.
  757.  
  758.     FIND/M  - Find the hex (in $xxxxx format) address in
  759.               the tracked segments.  Multiple addresses
  760.               can be given.
  761.  
  762.     Options are not available from Workbench as they require
  763.     the CLI.  However, you can run SegTracker from Workbench
  764.     to install it.
  765.  
  766.    EXAMPLE USAGE
  767.     /*
  768.      * A simple program that will "find" given addresses in the SegLists
  769.      * This program has been compiled with SAS/C 6.2 without errors or
  770.      * warnings.
  771.      *
  772.      * Compiler options:
  773.      * DATA=FARONLY PARAMETERS=REGISTER NOSTACKCHECK
  774.      * NOMULTIPLEINCLUDES STRINGMERGE STRUCTUREEQUIVALENCE
  775.      * MULTIPLECHARACTERCONSTANTS DEBUG=LINE NOVERSION
  776.      * OPTIMIZE OPTIMIZERINLOCAL NOICONS
  777.      *
  778.      * Linker options:
  779.      * FindSeg.o TO FindSeg SMALLCODE SMALLDATA NODEBUG LIB LIB:sc.lib
  780.      */
  781.     #include <exec/types.h>
  782.     #include <exec/execbase.h>
  783.     #include <exec/libraries.h>
  784.     #include <exec/semaphores.h>
  785.     #include <dos/dos.h>
  786.     #include <dos/dosextens.h>
  787.     #include <dos/rdargs.h>
  788.  
  789.     #include <clib/exec_protos.h>
  790.     #include <pragmas/exec_sysbase_pragmas.h>
  791.  
  792.     #include <clib/dos_protos.h>
  793.     #include <pragmas/dos_pragmas.h>
  794.  
  795.     #include <string.h>
  796.  
  797.     #include "FindSeg_rev.h"
  798.  
  799.     #define EXECBASE (*(struct ExecBase **)4)
  800.  
  801.     typedef char (* __asm SegTrack(register __a0 ULONG,
  802.                                    register __a1 ULONG *,
  803.                                    register __a2 ULONG *));
  804.  
  805.     struct SegSem
  806.     {
  807.     struct SignalSemaphore seg_Semaphore;
  808.            SegTrack        *seg_Find;
  809.     };
  810.  
  811.     #define SEG_SEM "SegTracker"
  812.  
  813.     #define TEMPLATE "FIND/M" VERSTAG
  814.  
  815.     #define OPT_FIND  0
  816.     #define OPT_COUNT 1
  817.  
  818.     ULONG cmd(void)
  819.     {
  820.     struct ExecBase *SysBase;
  821.     struct Library  *DOSBase;
  822.     struct RDArgs   *rdargs;
  823.            ULONG    rc=RETURN_FAIL;
  824.     struct SegSem   *segSem;
  825.            char     **hex;
  826.            LONG     opts[OPT_COUNT];
  827.  
  828.       SysBase = EXECBASE;
  829.       if (DOSBase = OpenLibrary("dos.library",37))
  830.       {
  831.         memset((char *)opts, 0, sizeof(opts));
  832.  
  833.         if (!(rdargs = ReadArgs(TEMPLATE, opts, NULL)))
  834.         {
  835.           PrintFault(IoErr(),NULL);
  836.         }
  837.         else if (CheckSignal(SIGBREAKF_CTRL_C))
  838.         {
  839.           PrintFault(ERROR_BREAK,NULL);
  840.         }
  841.         else if (segSem=(struct SegSem *)FindSemaphore(SEG_SEM))
  842.         {
  843.           rc=RETURN_OK;
  844.           if (opts[OPT_FIND])
  845.           {
  846.             for (hex=(char **)opts[OPT_FIND];(*hex);hex++)
  847.             {
  848.             char  *p;
  849.             ULONG val;
  850.             ULONG tmp[4];
  851.             ULONG c;
  852.  
  853.               val=0;
  854.               p=*hex;
  855.               if (*p=='$') p++; /* Support $hex */
  856.               while (*p)
  857.               {
  858.                 c=(ULONG)*p;
  859.                 if ((c>='a') && (c<='f')) c-=32;
  860.                 c-='0';
  861.                 if (c>9)
  862.                 {
  863.                   c-=7;
  864.                   if (c<10) c=16;
  865.                 }
  866.  
  867.                 if (c<16)
  868.                 {
  869.                   val=(val << 4) + c;
  870.                   p++;
  871.                 }
  872.                 else
  873.                 {
  874.                   val=0;
  875.                   p=&p[strlen(p)];
  876.                 }
  877.               }
  878.  
  879.               /*
  880.                * Ok, we need to do this within Forbid()
  881.                * as segments can unload at ANY time, including
  882.                * during AllocMem(), so we use a stack buffer...
  883.                *
  884.                */
  885.               Forbid();
  886.               if (p=(*segSem->seg_Find)(tmp[0]=val,&tmp[2],&tmp[3]))
  887.               {
  888.               char Buffer[200];
  889.  
  890.                 stccpy(Buffer,p,200);
  891.                 tmp[1]=(ULONG)Buffer;
  892.                 VPrintf("$%08lx - %s : Hunk %ld, Offset $%08lx\n",tmp);
  893.               }
  894.               else VPrintf("$%08lx - Not found\n",tmp);
  895.               Permit();
  896.             }
  897.           }
  898.         }
  899.         else PutStr("Could not find SegTracker semaphore.\n");
  900.  
  901.         if (rdargs) FreeArgs(rdargs);
  902.         CloseLibrary(DOSBase);
  903.       }
  904.       else if (DOSBase=OpenLibrary("dos.library",0))
  905.       {
  906.         Write(Output(),"Requires Kickstart 2.04 (37.175) or later.\n",43);
  907.         CloseLibrary(DOSBase);
  908.       }
  909.  
  910.       return(rc);
  911.     }
  912.  
  913.    NOTES
  914.     The earlier this command is run, the better off it will be in
  915.     tracking disk loaded segments.  Under debug usage, you may
  916.     wish to run the command right *AFTER* SetPatch.
  917.  
  918.     Some things may not call UnLoadSeg() to free their seglists.
  919.     There is no way SegTracker can follow a seglist that is not
  920.     unloaded via the dos.library call to UnLoadSeg().  For this
  921.     reason, SegTracker adds new LoadSeg() segments to the top
  922.     of its list.  This way, if any old segments are still on
  923.     the list but have been unloaded via some other method
  924.     they will not clash with newer segments during the find operation.
  925.  
  926.     Note that the resident list is one such place where
  927.     UnLoadSeg() is not called to free the seglist.  Thus,
  928.     if something is made resident and then later unloaded
  929.     it will still be listed as tracked by SegTracker.
  930.  
  931.    SEE ALSO
  932.     "Quantum Physics:  The Dreams that Stuff is made of." - Michael Sinz
  933.  
  934.    BUGS
  935.  
  936.